﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Abp;
using Abp.Domain.Repositories;
using Abp.ObjectMapping;
using Abp.Runtime.Caching;
using AutoMapper.QueryableExtensions;
using FwProject.Authorization.Users;
using FwProject.Car.Dto;
using FwProject.Core.Car;
using X.PagedList;
using FwProject.Manager;
using FwProject.Restaurant.Dto;
using FwProject.Restaurant;
using Abp.Authorization;
using FwProject.TypeNumber;
using FwProject.TypeNumber.Dto;
using Microsoft.EntityFrameworkCore;
using Abp.AutoMapper;
using FwProject.Core.Restaurant;
using Abp.Domain.Entities.Caching;
using System.Security.Claims;
using System.Threading;
using Microsoft.AspNetCore.Http;
using FwProject.Distribution;

namespace FwProject.Car
{
    [AbpAuthorize]
    public class CarInfoAppService:FwProjectAppServiceBase, ICarInfoAppService
    {
        public readonly IRepository<CarInfo, Guid> _repositoryCarInfo;
        public readonly ITypeNumberInfoAppService _itypeNumberInfoAppService;
        public readonly IRepository<User, long> _repositoryUser;
        public readonly IRepository<CarMap, Guid> _repositoryCarMap;
        public readonly IRepository<LoadCar, Guid> _repositoryLoadCar;
        public readonly IDriverTypeNumberAppService _driverTypeNumberAppService;
        private readonly CarInfoManager _carinfoManager;
        public readonly ICacheManager _catchmanager;
        public IGuidGenerator _guid { get; set; }
        public IObjectMapper _map { get; set; }
        public IHttpContextAccessor httpContextAccessor;
        public CarInfoAppService(
            ICacheManager catchmanager, IRepository<User, long> repositoryUser,
             IRepository<CarInfo, Guid> repositoryCarInfo,CarInfoManager carinfoManager,
             ITypeNumberInfoAppService itypeNumberInfoAppService,
             IRepository<CarMap, Guid> repositoryCarMap,
             IRepository<LoadCar, Guid> repositoryLoadCar,
             IDriverTypeNumberAppService driverTypeNumberAppService
             )     
        {
            _catchmanager = catchmanager;
            _repositoryUser = repositoryUser;
            _repositoryCarInfo = repositoryCarInfo;
            _carinfoManager = carinfoManager;
            _itypeNumberInfoAppService = itypeNumberInfoAppService;
            _repositoryCarMap = repositoryCarMap;
            _repositoryLoadCar = repositoryLoadCar;
            _guid = SequentialGuidGenerator.Instance;
            _driverTypeNumberAppService = driverTypeNumberAppService;


        }

        /// <summary>
        /// 添加一辆配送汽车
        /// </summary>
        /// <returns>The create.</returns>
        /// <param name="input">Input.</param>
        public async Task<Guid> Create(CarInfoInputDto input)
        {
            var usermodel = await _repositoryUser.GetAsync(input.EmployeeCarUserId);
            var model = _map.Map<CarInfo>(input);
            model.Id = _guid.Create();
            model.FactoryinfoId = usermodel.FactoryinfoId;
            return await _carinfoManager.CreateCar(model);
        }

        public async Task<long[]> GetCarUserIdList() {
            ///根据库管信息获取所有司机。
            var user =await _repositoryUser.GetAsync(AbpSession.UserId.Value);
            return  _repositoryUser.GetAll().Where(o => o.FactoryinfoId == user.FactoryinfoId && o.EmployeeType == EmployeeType.司机类型).Select(o => o.Id).ToArray();
            
        }

        /// <summary>
        /// 获取一辆配送汽车
        /// </summary>
        /// <returns>The by identifier async.</returns>
        /// <param name="id">Identifier.</param>
        public virtual async Task<CarInfoDto> GetByIdAsync(long id)
        {
         
            var model = (await GetCache).AsQueryable().Where(o => o.EmployeeCarUserId == id).FirstOrDefault();
            return _map.Map<CarInfoDto>(model);         

        }
        /// <summary>
        /// 获取一个车辆信息
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public virtual async Task<CarInfoDto> GetByCarIdAsync(Guid id)
        {
            
            var model = (await GetCache).Where(o => o.Id == id).FirstOrDefault();
            return _map.Map<CarInfoDto>(model);

        }



        /// <summary>
        /// 获取车辆信息和装车型号
        /// </summary>
        /// <returns>The by identifier async.</returns>
        /// <param name="id">Identifier.</param>
        public async Task<Tuple<CarInfoDto,List<TypeNumberInfoDto>>> GetByCarAndTypeNumberIdAsync(long id)
        {
            var model = (await GetCache).AsQueryable().Where(o => o.EmployeeCarUserId == id).FirstOrDefault();
            var car= _map.Map<CarInfoDto>(model);
            var typeNumber=await _itypeNumberInfoAppService.GetDefaultTypeNumber();
            return Tuple.Create(car, typeNumber);

        }
        /// <summary>
        /// App 司机获取装车型号新接口20181022
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public async Task<Tuple<CarInfoDto, List<TypeNumberInfoDto>>> GetByNewCarAndTypeNumberIdAsync(long id)
        {
            var model = (await GetCache).AsQueryable().Where(o => o.EmployeeCarUserId == id).FirstOrDefault();
            var car = _map.Map<CarInfoDto>(model);
            var typeNumber = await _driverTypeNumberAppService.GetDefaultDriverByTypeNumber();
            return Tuple.Create(car, typeNumber);

        }
        /// <summary>
        /// 获取配送汽车列表
        /// </summary>
        /// <returns>The restaurant paged list async.</returns>
        /// <param name="汽车编号">Page index.</param>
        public async Task<IPagedList<CarInfoDto>> GetPagedListAsync(int pageIdx, int pageSize, DateTime? begindateTime, DateTime? enddatetime)
        {
            var listmodel = (await GetCache).AsQueryable();
            if (begindateTime != null)
                listmodel.Where(o => o.CreationTime >= begindateTime);

            if (enddatetime != null)
                listmodel.Where(o => o.CreationTime <= enddatetime);

            var model = _repositoryCarInfo.GetAll().Where(o =>o.EmployeeCarUserId==AbpSession.UserId.Value).FirstOrDefault();
            return await listmodel.Where(o => o.Id == model.Id).ProjectTo<CarInfoDto>().ToPagedListAsync(pageIdx, pageSize);
        }
        /// <summary>
        /// 查询工厂下的所有汽车
        /// </summary>
        /// <param name="pageIdx"></param>
        /// <param name="pageSize"></param>
        /// <param name="begindateTime"></param>
        /// <param name="enddatetime"></param>
        /// <param name="factoryid"></param>
        /// <param name="keyword"></param>
        /// <returns></returns>
        public async Task<IPagedList<CarInfoDto>> GetAllPagedListAsync(int pageIdx, int pageSize, DateTime? begindateTime, DateTime? enddatetime, string factoryid,string keyword)
        {
            var listmodel = (await GetCache).AsQueryable();
            if (begindateTime != null)
                listmodel= listmodel.Where(o => o.CreationTime >= begindateTime);

            if (enddatetime != null)
                listmodel= listmodel.Where(o => o.CreationTime <= enddatetime);


            if (!string.IsNullOrWhiteSpace(factoryid))
            {
                Guid fid = new Guid(factoryid);
                listmodel= listmodel.Where(o => o.FactoryinfoId == fid);
            }

            if (!string.IsNullOrWhiteSpace(keyword))
                listmodel = listmodel.Where(o => o.PlatesNumber.Contains(keyword));
                

            return await listmodel.ProjectTo<CarInfoDto>().ToPagedListAsync(pageIdx, pageSize);
        }

        public async Task<List<CarInfoDto>> GetCarListAsync()
        {
            var usermodel = await _repositoryUser.GetAsync(AbpSession.UserId.Value);
            var listmodel = (await GetCache).AsQueryable().Where(o => o.FactoryinfoId == usermodel.FactoryinfoId);
            return listmodel.ProjectTo<CarInfoDto>().ToList();
        }
        /// <summary>
        /// 修改配送汽车
        /// </summary>
        /// <returns>The update.</returns>
        /// <param name="id">Identifier.</param>
        /// <param name="input">Input.</param>
        public async Task Update(Guid id, CarInfoInputDto input)
        {
            var model = await _repositoryCarInfo.GetAsync(id);
            model = _map.Map(input, model);
            await _carinfoManager.UpdateCar(model);

        }
        /// <summary>
        /// 删除一辆汽车
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public async Task Delete(Guid id)
        {
            var entity = await _repositoryCarInfo.GetAsync(id);
            await _repositoryCarInfo.DeleteAsync(entity);
        }
        /// <summary>
        /// 返回工厂所有司机
        /// </summary>
        /// <returns></returns>
        public async Task<List<CarInfoDto>> GetAllDriver()
        {
           var user=await _repositoryUser.GetAsync(AbpSession.UserId.Value);
            long[] drivers = _repositoryUser.GetAll().Where(o => o.FactoryinfoId == user.FactoryinfoId).Select(o => o.Id).ToArray();
           return _map.Map<List<CarInfoDto>>((await GetCache).Where(o => drivers.Any(s => s == o.EmployeeCarUserId)));
        }


        public async Task<List<CarTrackOutputDto>> GetCarTrackAsync(string keyword)
        {
            //获取当前登录人
            var user = await _repositoryUser.GetAsync(AbpSession.UserId.Value);
            //根据当前登录人获取该工厂下所有车辆信息
            var cars = (await GetCache).AsQueryable().Where(o => o.FactoryinfoId == user.FactoryinfoId);
            if (!string.IsNullOrWhiteSpace(keyword))
                cars = cars.Where(o => o.PlatesNumber.Contains(keyword));


            var data = cars.MapTo<List<CarTrackOutputDto>>();

            foreach (var item in data)
            {
                var map = await _repositoryCarMap.GetAll().Where(o => o.CarInfoId == item.Id).OrderByDescending(o => o.CreationTime).FirstOrDefaultAsync();
                if (map!=null)
                {
                    item.EndCarMap = map.MapTo<CarTrackOutputDto.EndCarMapDto>();
                }
                var status = await _repositoryLoadCar.GetAll().Where(o => o.CarInfoId == item.Id).OrderByDescending(o => o.CreationTime).FirstOrDefaultAsync();
                if (status!=null)
                {
                    item.EndLoadCar = new CarTrackOutputDto.EndLoadCarDto();
                    item.EndLoadCar.CarStatus = status.CarStatus;
                }
               
            }

            return data;
        }

        private Task<List<CarInfo>> GetCache
        {
            get
            {
               
                ICache cache = _catchmanager.GetCache(nameof(CarInfo));
                return cache.GetAsync($"list", async () => await _repositoryCarInfo.GetAllIncluding(o=>o.CarUser).Where(o=>o.IsDeleted==false).ToListAsync());
            }

        }
    }
}
